package net.mgsx.product.t2m.modisco.quality;
import java.util.Collection;

import net.mgsx.product.t2m.modisco.tools.ModiscoUtils;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.FieldAccess;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.infra.query.core.exception.ModelQueryExecutionException;
import org.eclipse.gmt.modisco.infra.query.core.java.IJavaModelQuery;
import org.eclipse.gmt.modisco.infra.query.core.java.ParameterValueList;

/**
 * A method should be static if :
 * - there is no access to any of its own attributes including
 * derivate attributes.
 * 
 * @author mgsx
 *
 */
public class ShouldBeStatic implements IJavaModelQuery<MethodDeclaration, Boolean> {
	public Boolean evaluate(final MethodDeclaration context, final ParameterValueList parameterValues)
			throws ModelQueryExecutionException {
		if(context.getModifier() != null && context.getModifier().isStatic())
		{
			return false;
		}
		boolean result = false;
		Collection<FieldAccess> allFieldAccess = ModiscoUtils.getElements(context, FieldAccess.class);
		AbstractTypeDeclaration methodOwner = context.getAbstractTypeDeclaration();
		if(methodOwner instanceof ClassDeclaration)
		{
			result = true;
			for(FieldAccess fieldAccess : allFieldAccess)
			{
				EObject container = fieldAccess.getField().getVariable().eContainer();
				if(container instanceof ClassDeclaration){
					if(isChildClass((ClassDeclaration)container, (ClassDeclaration)methodOwner)){
						result = false;
						break;
					}
				}
			}
		}
		return result;
	}
	
	private boolean isChildClass(ClassDeclaration anyClass, ClassDeclaration childClass)
	{
		if(anyClass == null)
		{
			return false;
		}
		if(anyClass == childClass)
		{
			return true;
		}
		if(childClass.getSuperClass() == null || !(childClass.getSuperClass() instanceof ClassDeclaration))
		{
			return false;
		}
		return isChildClass(anyClass, (ClassDeclaration)childClass.getSuperClass().getType());
	}
}
